package cn.watson.basic.service.impl;

import cn.watson.basic.constant.BaseConstants;
import cn.watson.basic.dto.SmsCodeDto;
import cn.watson.basic.exception.BusinessException;
import cn.watson.basic.service.IVerifyCodeService;
import cn.watson.basic.utils.StrUtils;
import cn.watson.basic.utils.VerifyCodeUtils;
import cn.watson.user.domain.User;
import cn.watson.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    // 注入Redis
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    /**
    * @Title: getImageCode
    * @Description: 图形验证码
    * @Author: ZhangRui
    * @Version: 1.0
    * @Date:  2022/7/6 16:09
    * @Parameters: [key]
    * @Return java.lang.String
    */
    @Override
    public String getImageCode(String key) {
        // 1.判断传递的key是否为null
        if (StringUtils.isEmpty(key)){
            throw new BusinessException("参数不能为空！");
        }

        // 2.调用字符串工具类，获取4为随机字符
        String code = StrUtils.getComplexRandomString(4);

        // 将随机字符串放到redis中 并设置有效时间
        redisTemplate.opsForValue().set(key, code, 5 , TimeUnit.MINUTES);

        // 将code值生成图片，并编码base64
        String base64Str = VerifyCodeUtils.VerifyCode(100, 35, code);
        return base64Str;
    }

    /**
    * @Title: smsCode
    * @Description: 发送短信验证码
    * @Author: ZhangRui
    * @Version: 1.0
    * @Date:  2022/7/6 16:10  
    * @Parameters: [smsCodeDto]
    * @Return void
    */
    @Override
    public void smsCode(SmsCodeDto smsCodeDto) {
        // 1.获取手机号，图形验证码，图形验证码Rediskey的值
        String phone = smsCodeDto.getPhone();

        // 业务类型type
        String type = smsCodeDto.getType();

        // 获取图形验证码
        /*String imageCodeValue = smsCodeDto.getImageCodeValue();
        // 获取到Redis中的Key的值
        String imageCodeKey = smsCodeDto.getImageCodeKey();*/

        // 2.非空校验 判断参数是否为空
        // 判断手机号码是否为空
        if(StringUtils.isEmpty(phone)){
            throw new BusinessException("参数不能为空！");
        }
        if ("register".equals(type)){
            // 校验图形验证码是否正确
            checkImageCode(smsCodeDto);
            //3.判断用户是否已注册，如果已注册提示用户
            User user = userMapper.loadByPhone(phone);
            if (user != null){
                throw new BusinessException("用户已注册，请直接登录，如果忘记密码，请点击忘记密码！");
            }
            sendCode(BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_KEY, phone);
        }else if ("binder".equals(type)){ // 2.2.微信绑定账号业务,发送短信验证码
            sendCode(BaseConstants.VerifyCodeConstant.BUSINESS_BINDER_KEY, phone);
        }
    }

    /**
    * @Title: checkImageCode
    * @Description: 校验图形验证码
    * @Author: ZhangRui
    * @Version: 1.0
    * @Date:  2022/7/10 23:08
    * @Parameters: [smsCodeDto]
    * @Return void
    */
    public void checkImageCode(SmsCodeDto smsCodeDto){
        // 图形验证码的key
        String imageCodeKey = smsCodeDto.getImageCodeKey();
        // 图形验证码的value
        String imageCodeValue = smsCodeDto.getImageCodeValue();
        //1.非空校验
        if (StringUtils.isEmpty(imageCodeKey) || StringUtils.isEmpty(imageCodeValue)){
            throw new BusinessException("参数不能为空！");
        }
        //2.判断图形验证码是否正确以及存在
        Object imageCodeValueTmp = redisTemplate.opsForValue().get(imageCodeKey);
        if (imageCodeValueTmp == null){
            throw new BusinessException("验证码已过期，请重新获取！");
        }
        // 忽略大小写比较图形验证码是否正确
        if (!imageCodeValueTmp.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("验证码错误，请重新输入！");
        }
    }

    /**
    * @Title: sendCode
    * @Description:  发送手机验证码
    * @Author: ZhangRui
    * @Version: 1.0
    * @Date:  2022/7/10 23:09
    * @Parameters: [businessKey, phone]
    * @Return void
    */
    public void sendCode(String businessKey, String phone){
        //4.根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
        String phoneCodeKey = businessKey + phone;
        Object phoneCodeValue = redisTemplate.opsForValue().get(phoneCodeKey);
        //0.定义一个空字符串，专门用来接收验证码
        String phoneCode = "";
        if (phoneCodeValue == null){//1.不存在
            //1.生成新的随机验证码,并赋值给空字符串
            phoneCode = StrUtils.getComplexRandomString(4);
        }else {//2.存在
            //1.分割value得到时间戳，跟现在的时间戳做减法，如果小于1分钟的毫秒数抛出异常
            String[] phoneCodeValueTmp = phoneCodeValue.toString().split(":");
            // 之前存入code时，我们记录的时间戳
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 得到现在的时间戳
            Long nowTime = System.currentTimeMillis();
            if (nowTime - oldTime < 1*60*1000){
                throw new BusinessException("请一分钟之后再获取！");
            }
            //2.将旧的验证码赋值给空字符串
            phoneCode = phoneCodeValueTmp[1];
        }
        //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
        String phoneCodeRedis = System.currentTimeMillis() + ":" + phoneCode;
        redisTemplate.opsForValue().set(phoneCodeKey, phoneCodeRedis, 3, TimeUnit.MINUTES);
        //6.发送短信验证码
        // SmsUtils.sendCode(phone, "亲，您的验证码是："+ phoneCode);
        System.out.println("亲，您的验证码是："+ phoneCode);
    }


        // 判断图形验证码是否正确，或者存在
        /*Object imageCodeValueTmp  = redisTemplate.opsForValue().get(imageCodeKey);
        if (imageCodeValueTmp == null){
            throw new BusinessException("验证码已经过期，请重新获取！！");
        }
        // 比较图形验证码是否正确            equalsIgnoreCase(imageCodeValue),忽略大小写
        if(!imageCodeValueTmp.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("验证码错误，请重新输入！！");
        }

        // 3.判断用户是否已经注册，已注册侧提示用户
        User user = userMapper.loadByPhone(phone);
        if (user != null){
            throw new BusinessException("用户已经注册，请直接登录！！");
        }

        // 4.根据电话号码拼接业务键值，去redis中获取对应的Value值，判断是否存在;
        // 【先拼接】将redis中的业务建+电话号码，
        String phoneCodeKey  = BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_KEY + phone;
        // 获取到拼接的数据
        Object phoneCodeValue = redisTemplate.opsForValue().get(phoneCodeKey);
        // 定义一个空字符串，用来接收验证码
        String phoneCode = "";
        // 判断是否存在
        if (phoneCodeValue == null){
            // 不存在。生成新的随机验证码，并赋值给空字符串
             phoneCode = StrUtils.getComplexRandomString(4);
        }else {
            // 存在。分割value得到时间戳，更现在的时间做减法，小于1分钟的毫秒数，就抛出异常
            String[] phoneCodeValueTmp = phoneCodeValue.toString().split(":");
            // 存入code时，开始记录时间戳
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 现在时间戳
            long nowTime = System.currentTimeMillis();
            if (nowTime - oldTime < 1*60*1000){
                throw new BusinessException("请一分钟后在获取！");
            }
            // 将旧验证码赋值给空字符串
            phoneCode = phoneCodeValueTmp[1];
        }
        // 5.通过业务键+phone,作为key。验证码+时间戳作为Value。存入Redis,并设置有效时间
        // 得到键Key
        String phoneCodeRedis = System.currentTimeMillis()+ ":" + phoneCode;
        redisTemplate.opsForValue().set(phoneCodeKey, phoneCodeRedis, 3, TimeUnit.MINUTES);
        //6.发送短信验证码
        // SmsUtils.sendCode(phone, "亲，您的验证码是："+ phoneCode);  // 需要真实手机验证码时 放开该字段
        System.out.println("亲，您的验证码是："+ phoneCode);
    }*/
}
